package com.kexio.user.service;

import java.util.List;
import java.util.Map;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kexio.user.entity.Menu;
import com.kexio.user.entity.Permission;
import com.kexio.user.entity.Role;

/**
 * 菜单服务接口
 * 
 * 提供菜单管理的核心业务逻辑，包括：
 * - 菜单CRUD操作
 * - 菜单树形结构管理
 * - 菜单权限关联
 * - 用户菜单过滤
 * - 导航菜单构建
 * - 多租户数据隔离
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
public interface MenuService {
    
    // ==================== 基础CRUD操作 ====================
    
    /**
     * 创建菜单
     * 
     * @param menu 菜单信息
     * @return 创建的菜单信息
     */
    Menu createMenu(Menu menu);
    
    /**
     * 根据ID更新菜单信息
     * 
     * @param menuId 菜单ID
     * @param menu 更新的菜单信息
     * @return 更新后的菜单信息
     */
    Menu updateMenu(String menuId, Menu menu);
    
    /**
     * 根据ID删除菜单（逻辑删除）
     * 
     * @param menuId 菜单ID
     * @return 是否删除成功
     */
    boolean deleteMenu(String menuId);
    
    /**
     * 根据ID查询菜单信息
     * 
     * @param menuId 菜单ID
     * @return 菜单信息
     */
    Menu getMenuById(String menuId);
    
    /**
     * 根据菜单编码查询菜单信息
     * 
     * @param menuCode 菜单编码
     * @return 菜单信息
     */
    Menu getMenuByCode(String menuCode);
    
    // ==================== 菜单列表查询 ====================
    
    /**
     * 分页查询菜单列表
     * 
     * @param current 当前页码
     * @param size 每页大小
     * @return 分页菜单列表
     */
    Page<Menu> getMenuPage(Long current, Long size);
    
    /**
     * 带条件分页查询菜单列表
     * 
     * @param tenantId 租户ID
     * @param current 当前页码
     * @param size 每页大小
     * @param menuType 菜单类型（可选）
     * @param menuName 菜单名称（可选）
     * @param status 状态（可选）
     * @return 分页菜单列表
     */
    Page<Menu> getMenuPage(Long current, Long size,
                           String menuType, String menuName, Integer status);
    
    /**
     * 查询租户下的所有菜单
     * 
     * @param tenantId 租户ID
     * @return 菜单列表
     */
    List<Menu> getMenusByTenant(String tenantId);
    
    /**
     * 根据菜单类型查询菜单列表
     * 
     * @param menuType 菜单类型
     * @param tenantId 租户ID
     * @return 菜单列表
     */
    List<Menu> getMenusByType(String menuType, String tenantId);
    
    /**
     * 查询启用且可见的菜单列表
     * 
     * @param tenantId 租户ID
     * @return 可见菜单列表
     */
    List<Menu> getVisibleMenus(String tenantId);
    
    // ==================== 菜单树形结构 ====================
    
    /**
     * 查询完整菜单树结构
     * 
     * @param tenantId 租户ID
     * @return 菜单树列表（已构建父子关系）
     */
    List<Menu> getMenuTree(String tenantId);
    
    /**
     * 查询菜单的直接子菜单
     * 
     * @param parentMenuId 父菜单ID
     * @param tenantId 租户ID
     * @return 子菜单列表
     */
    List<Menu> getChildMenus(String parentMenuId);
    
    /**
     * 查询菜单的所有祖先菜单
     * 
     * @param menuId 菜单ID
     * @param tenantId 租户ID
     * @return 祖先菜单列表
     */
    List<Menu> getAncestorMenus(String menuId, String tenantId);
    
    /**
     * 查询菜单的所有后代菜单
     * 
     * @param menuId 菜单ID
     * @param tenantId 租户ID
     * @return 后代菜单列表
     */
    List<Menu> getDescendantMenus(String menuId, String tenantId);
    
    /**
     * 查询根菜单列表（没有父菜单的菜单）
     * 
     * @param tenantId 租户ID
     * @return 根菜单列表
     */
    List<Menu> getRootMenus(String tenantId);
    
    // ==================== 用户菜单权限 ====================
    
    /**
     * 查询用户有权限访问的菜单列表
     * 
     * @param userId 用户ID
     * @param tenantId 租户ID
     * @return 菜单列表
     */
    List<Menu> getUserMenus(String userId);
    
    /**
     * 查询用户有权限访问的菜单树
     * 
     * @param userId 用户ID
     * @param tenantId 租户ID
     * @return 用户菜单树列表
     */
    List<Menu> getUserMenuTree(String userId, String tenantId);
    
    /**
     * 查询用户的导航菜单
     * 
     * 仅返回用户有权限且需要显示在导航中的菜单
     * 
     * @param userId 用户ID
     * @param tenantId 租户ID
     * @return 导航菜单列表
     */
    List<Menu> getUserNavMenus(String userId, String tenantId);
    
    /**
     * 检查用户是否有菜单访问权限
     * 
     * @param userId 用户ID
     * @param menuId 菜单ID
     * @param tenantId 租户ID
     * @return 是否有权限
     */
    boolean hasMenuAccess(String userId, String menuId);
    
    // ==================== 角色菜单查询 ====================
    
    /**
     * 查询角色关联的菜单列表
     * 
     * @param roleId 角色ID
     * @param tenantId 租户ID
     * @return 菜单列表
     */
    List<Menu> getMenusByRole(String roleId);
    
    /**
     * 查询角色菜单树结构
     * 
     * @param roleId 角色ID
     * @param tenantId 租户ID
     * @return 角色菜单树列表
     */
    List<Menu> getRoleMenuTree(String roleId, String tenantId);
    
    /**
     * 查询拥有指定菜单访问权限的角色列表
     * 
     * @param menuId 菜单ID
     * @param tenantId 租户ID
     * @return 角色列表
     */
    List<Role> getRolesByMenu(String menuId, String tenantId);
    
    // ==================== 菜单权限关联 ====================
    
    /**
     * 查询菜单关联的权限列表
     * 
     * @param menuId 菜单ID
     * @param tenantId 租户ID
     * @return 权限列表
     */
    List<Permission> getMenuPermissions(String menuId, String tenantId);
    
    /**
     * 查询权限关联的菜单列表
     * 
     * @param permissionId 权限ID
     * @param tenantId 租户ID
     * @return 菜单列表
     */
    List<Menu> getMenusByPermission(String permissionId, String tenantId);
    
    /**
     * 移除菜单的权限
     * 
     * @param menuId 菜单ID
     * @param permissionIds 权限ID列表
     * @param tenantId 租户ID
     * @return 是否移除成功
     */
    boolean removePermissions(String menuId, List<String> permissionIds, String tenantId);
    
    // ==================== 导航相关 ====================
    
    /**
     * 构建面包屑导航路径
     * 
     * @param menuId 当前菜单ID
     * @param tenantId 租户ID
     * @return 面包屑菜单列表（从根到当前）
     */
    List<Menu> buildBreadcrumbPath(String menuId);
    
    /**
     * 获取菜单的完整路径
     * 
     * @param menuId 菜单ID
     * @param tenantId 租户ID
     * @return 路径字符串（如：/system/user/list）
     */
    String getMenuFullPath(String menuId, String tenantId);
    
    /**
     * 根据路径查找菜单
     * 
     * @param menuPath 菜单路径
     * @param tenantId 租户ID
     * @return 菜单信息
     */
    Menu getMenuByPath(String menuPath, String tenantId);
    
    // ==================== 菜单排序管理 ====================
    
    /**
     * 调整菜单排序
     * 
     * @param menuId 菜单ID
     * @param newSortOrder 新的排序号
     * @param tenantId 租户ID
     * @param operatorId 操作者ID
     * @return 是否调整成功
     */
    boolean updateMenuSort(String menuId, Integer newSortOrder, String tenantId, String operatorId);
    
    /**
     * 获取同级菜单的下一个排序号
     * 
     * @param parentMenuId 父菜单ID
     * @param tenantId 租户ID
     * @return 下一个排序号
     */
    Integer getNextSortOrder(String parentMenuId);
    
    /**
     * 批量调整同级菜单排序
     * 
     * @param parentMenuId 父菜单ID
     * @param menuIdSortMap 菜单ID和排序号映射
     * @param tenantId 租户ID
     * @param operatorId 操作者ID
     * @return 是否调整成功
     */
    boolean batchUpdateMenuSort(String parentMenuId, java.util.Map<String, Integer> menuIdSortMap, String tenantId, String operatorId);
    
    // ==================== 统计查询 ====================
    
    /**
     * 统计租户菜单总数
     * 
     * @param tenantId 租户ID
     * @return 菜单总数
     */
    Long countMenusByTenant(String tenantId);
    
    /**
     * 统计启用的菜单数量
     * 
     * @param tenantId 租户ID
     * @return 启用菜单数
     */
    Long countActiveMenus(String tenantId);
    
    /**
     * 统计各类型菜单数量
     * 
     * @param tenantId 租户ID
     * @return 类型统计结果 Map<菜单类型, 数量>
     */
    Map<String, Long> countMenusByType(String tenantId);
    
    /**
     * 统计菜单的子菜单数量
     * 
     * @param parentMenuId 父菜单ID
     * @param tenantId 租户ID
     * @return 子菜单数量
     */
    Long countChildMenus(String parentMenuId, String tenantId);
    
    // ==================== 数据验证 ====================
    
    /**
     * 检查菜单编码是否存在
     * 
     * @param menuCode 菜单编码
     * @param tenantId 租户ID
     * @param excludeMenuId 排除的菜单ID（用于更新时检查）
     * @return 是否存在
     */
    boolean existsByCode(String menuCode, String excludeMenuId);
    
    /**
     * 检查菜单名称是否存在（同级菜单中）
     * 
     * @param menuName 菜单名称
     * @param parentMenuId 父菜单ID
     * @param tenantId 租户ID
     * @param excludeMenuId 排除的菜单ID（用于更新时检查）
     * @return 是否存在
     */
    boolean existsByName(String menuName, String parentMenuId, String excludeMenuId);
    
    /**
     * 检查菜单路径是否唯一
     * 
     * @param menuPath 菜单路径
     * @param tenantId 租户ID
     * @param excludeMenuId 排除的菜单ID（用于更新时检查）
     * @return 是否唯一
     */
    boolean isMenuPathUnique(String menuPath, String tenantId, String excludeMenuId);
    
    /**
     * 检查菜单是否有子菜单
     * 
     * @param menuId 菜单ID
     * @param tenantId 租户ID
     * @return 是否有子菜单
     */
    boolean hasChildMenus(String menuId);
    
    /**
     * 检查是否会形成循环引用
     * 
     * @param menuId 菜单ID
     * @param newParentMenuId 新的父菜单ID
     * @param tenantId 租户ID
     * @return 是否会形成循环引用
     */
    boolean wouldCreateCircularReference(String menuId, String newParentMenuId);
    
    // ==================== 缓存管理 ====================
    
    /**
     * 刷新菜单缓存
     * 
     * @param tenantId 租户ID
     */
    void refreshMenuCache();
    
    /**
     * 刷新用户菜单缓存
     * 
     * @param userId 用户ID
     * @param tenantId 租户ID
     */
    void refreshUserMenuCache(String userId, String tenantId);
    
    /**
     * 菜单变更通知
     * 
     * 在菜单发生变更时调用，用于：
     * - 增加权限版本号
     * - 清除相关缓存
     * - 发送变更通知
     * 
     * @param menuId 菜单ID
     * @param tenantId 租户ID
     * @param operatorId 操作者ID
     */
    void notifyMenuChange(String menuId, String operatorId);
    
    // ==================== 用户可见菜单查询 ====================
    
    /**
     * 查询用户可见的菜单列表
     * 
     * @param userId 用户ID
     * @param tenantId 租户ID
     * @return 用户可见菜单列表
     */
    List<Menu> getUserVisibleMenus(String userId, String tenantId);
    
    // ==================== 菜单权限分配简化接口 ====================
    
    // ==================== 菜单状态管理 ====================
    
    /**
     * 更新菜单状态
     * 
     * @param menuId 菜单ID
     * @param status 状态：1-启用，0-禁用
     * @param tenantId 租户ID
     * @return 是否更新成功
     */
    boolean updateMenuStatus(String menuId, Integer status, String tenantId);
    
    /**
     * 更新菜单可见性
     * 
     * @param menuId 菜单ID
     * @param visible 是否可见
     * @param tenantId 租户ID
     * @return 是否更新成功
     */
    boolean updateMenuVisible(String menuId, Boolean visible, String tenantId);
}
